from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView,View
from django.db.models import Max, Count, Case, When, IntegerField, Q, F
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
import json
import datetime
import pandas as pd
import numpy as np
from tushare_data.models import IndexDaily, IndexWeekly, IndexMonthly, IndexMinuteData, TradeDate,StockMinuteData,DailyData,DailyBasic,StockBasic,ThsPlate,ThsStockPlate
from data_analysis.models import MarketSummary
from tushare_data.models import StockKDataWeekly,StockKDataMonthly

from rest_framework.views import APIView
from rest_framework.response import Response
from tushare_data.models import IndexDaily, IndexMinuteData, IndexWeekly, IndexMonthly
from datetime import datetime, timedelta
from django.db.models import Q
from .utils import *

class MarketIndicesView(APIView):
    """
    获取主要大盘指数数据
    """
    def get(self, request):
        # 定义主要指数代码
        indices = {
            'shanghai': '000001.SH',  # 上证指数
            'shenzhen': '399001.SZ',  # 深证成指
            'csi300': '000300.SH',    # 沪深300
            'gem': '399006.SZ'        # 创业板指
        }
        # 从IndexDaily表中获取最新的trade_date
        latest_record = IndexDaily.objects.order_by('-trade_date').first()
        if not latest_record:
            return Response({"error": "没有找到指数数据"}, status=404)
        latest_date = latest_record.trade_date
        # print(f'latest_date: {latest_date}')
        # 查询指数数据
        results = {
            'latest_date': latest_date,  # 添加格式化后的最新交易日期到返回数据中
            'indices': {}
        }
        for name, ts_code in indices.items():
            data = IndexDaily.objects.filter(
                ts_code=ts_code,
                trade_date=latest_date
            ).first()
            
            if data:
                results['indices'][name] = {
                    'close': data.close,
                    'change': data.change,
                    'pct_chg': data.pct_chg
                }
            else:
                # 如果没有找到数据，添加空对象
                results['indices'][name] = {
                    'close': None,
                    'change': None,
                    'pct_chg': None
                }
        return Response(results)


class IndexDailyKLineView(APIView):
    """
    获取指数日K线数据
    默认获取近两年的数据，但前端只显示近三个月的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SH')
        
        # 计算近两年的日期
        end_date = datetime.now()
        start_date = end_date - timedelta(days=365*2)
        
        # 从IndexDaily表中获取数据
        kline_data = IndexDaily.objects.filter(
            ts_code=ts_code,
            trade_date__gte=start_date.strftime('%Y%m%d')
        ).order_by('trade_date')

        print(f'kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount * 0.001 # 成交量,以百万为单位，兼容个股
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        # print(f'results: {results}')
        return Response(results)


class IndexWeeklyKLineView(APIView):
    """
    获取指数周K线数据
    默认获取近两年的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SH')
        
        # 计算近两年的日期
        end_date = datetime.now()
        start_date = end_date - timedelta(days=365*5)
        
        # 从IndexWeekly表中获取数据
        kline_data = IndexWeekly.objects.filter(
            ts_code=ts_code,
            trade_date__gte=start_date.strftime('%Y%m%d')
        ).order_by('trade_date')

        print(f'weekly_kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount* 0.000001  # 成交量，以亿为单位
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        return Response(results)


class IndexMonthlyKLineView(APIView):
    """
    获取指数月K线数据
    默认获取近五年的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SH')
        
        # 计算近五年的日期
        end_date = datetime.now()
        start_date = end_date - timedelta(days=365*10)
        
        # 从IndexMonthly表中获取数据
        kline_data = IndexMonthly.objects.filter(
            ts_code=ts_code,
            trade_date__gte=start_date.strftime('%Y%m%d')
        ).order_by('trade_date')

        print(f'monthly_kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount* 0.000001  # 成交量，以百万为单位
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        return Response(results)


class IndexMinuteDataView(APIView):
    """
    获取指数分时数据
    默认返回最近5个交易日的分时数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SH')
        # print(f'ts_code: {ts_code}')
        ts_code_akshare = get_akshare_code(ts_code)
        
        # 获取最近5个交易日的日期
        from django.db.models import Max
        latest_date = IndexMinuteData.objects.filter(
            ts_code=ts_code_akshare
        ).aggregate(Max('trade_time'))['trade_time__max']
        
        if not latest_date:
            return Response({"error": "没有找到分时数据"}, status=404)
            
        # 计算5个交易日前的日期
        from tushare_data.models import TradeDate
        trade_dates = TradeDate.objects.filter(
            is_open=1,
            cal_date__lte=latest_date.date().strftime('%Y%m%d')
        ).order_by('-cal_date').values_list('cal_date', flat=True)[:5]
        # print(f'trade_dates: {trade_dates}')
        if not trade_dates:
            return Response({"error": "无法确定交易日范围"}, status=404)
            
        start_date = list(trade_dates)[-1]
        
        # 查询分时数据
        
        # print(f'ts_code_akshare: {ts_code_akshare} start_date: {start_date} ts_code: {ts_code}')
        minute_data = IndexMinuteData.objects.filter(
            ts_code=ts_code_akshare,
            trade_time__date__gte=datetime.strptime(start_date, '%Y%m%d')          
        ).order_by('trade_time')
        
        # 准备返回数据
        results = {
            'ts_code': ts_code,
            'data': []
        }
        
        for data in minute_data:
            results['data'].append({
                'time': data.trade_time.astimezone().strftime('%Y-%m-%d %H:%M'),  # 转换为本地时区
                'price': float(data.close),
                'vol': int(data.vol),
            })
        # print(f'len of results: {len(results["data"])}')
            
        return Response(results)


class MarketDistributionView(View):
    def get(self, request):
        # 从data_analysis的MarketSummary模型中获取最新交易日的数据
        from data_analysis.models import MarketSummary
        
        # 获取最新的交易日期
        latest_date = MarketSummary.objects.aggregate(Max('date'))['date__max']
        print(f'latest_date: {latest_date}')
        
        # 获取最新交易日的市场摘要数据
        market_summary = MarketSummary.objects.get(date=latest_date)
        
        # 构建涨跌分布数据，转换为前端期望的格式
        distribution_data = [
            {'range': '涨停', 'count': market_summary.limit_up_stocks or 0},
            {'range': '>7%', 'count': market_summary.up_7_pct or 0},
            {'range': '7-5%', 'count': market_summary.up_5_to_up_7_pct or 0},
            {'range': '5-2%', 'count': market_summary.up_2_to_5_pct or 0},
            {'range': '2-0%', 'count': market_summary.up_0_to_2_pct or 0},
            {'range': '平', 'count': market_summary.flat_stocks or 0},
            {'range': '0-2%', 'count': market_summary.down_0_to_2_pct or 0},
            {'range': '2-5%', 'count': market_summary.down_2_to_5_pct or 0},
            {'range': '5-7%', 'count': market_summary.down_5_to_7_pct or 0},
            {'range': '7%<', 'count': market_summary.down_7_pct or 0},
            {'range': '跌停', 'count': market_summary.limit_down_stocks or 0},
        ]
        
        return JsonResponse({
            'distribution': distribution_data,
            'trade_date': latest_date,
            'total': market_summary.total_stocks or 0
        })


class MarketTrendView(View):
    def get(self, request):
        # 从data_analysis的MarketSummary模型中获取最近60个交易日的数据
        from data_analysis.models import MarketSummary
        
        # 获取最近60个交易日的市场摘要数据
        market_summaries = MarketSummary.objects.order_by('-date')[:60]
        
        # 构建市场趋势数据，转换为前端期望的格式
        trend_data = []
        for summary in market_summaries:
            trend_data.append({
                'date': summary.date,
                'up_count': summary.up_stocks or 0,
                'down_count': summary.down_stocks or 0,
                # 'total': summary.total_stocks or 0
            })
        
        # 按日期升序排序
        trend_data.sort(key=lambda x: x['date'])
        
        return JsonResponse({'trend': trend_data})
class MarketEnergyView(View):
    def get(self, request):
        from data_analysis.models import AmountEnergy
        # 获取最近60个交易日的市场摘要数据
        amount_energies = AmountEnergy.objects.order_by('-date')[:60]
        
        # 构建市场趋势数据，转换为前端期望的格式
        energy_data = []
        for amount_energy in amount_energies:
            energy_data.append({
                'trade_date': amount_energy.date,
                'amount_hs': amount_energy.hs_amount* 0.00001,  # 成交量，以亿为单位
                'amount_sh': amount_energy.sh_amount* 0.00001,  # 成交量，以亿为单位
                'amount_sz': amount_energy.sz_amount* 0.00001,  # 成交量，以亿为单位
                'amount_cyb': amount_energy.cyb_amount* 0.00001  # 成交量，以亿为单位
            })
        
        # 按日期升序排序
        energy_data.sort(key=lambda x: x['trade_date'])
        
        return JsonResponse({'energy': energy_data})  

class StockMinuteView(View):
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('code', '000001.SH')
        day = request.GET.get('day', '5')
        print(f'ts_code: {ts_code} day: {day}')


        
        # 获取最近5个交易日的日期
        from django.db.models import Max
        latest_date = StockMinuteData.objects.filter(
            ts_code=ts_code
        ).aggregate(Max('trade_time'))['trade_time__max']
        
        if not latest_date:
            return Response({"error": "没有找到分时数据"}, status=404)
            
        # 计算5个交易日前的日期
        if day == '5':
            trade_dates = TradeDate.objects.filter(
                is_open=1,
                cal_date__lte=latest_date.date().strftime('%Y%m%d')
            ).order_by('-cal_date').values_list('cal_date', flat=True)[:5]#默认从大到小排列
            # print(f'trade_dates: {trade_dates}')
            start_date = list(trade_dates)[-1]
        else:
            trade_dates = TradeDate.objects.filter(
                is_open=1,
                cal_date__lte=latest_date.date().strftime('%Y%m%d')
            ).order_by('-cal_date').values_list('cal_date', flat=True)[:1]#默认从大到小排列
            start_date = list(trade_dates)[0]
        if not trade_dates:
            return Response({"error": "无法确定交易日范围"}, status=404)
            
        
        
        # 查询分时数据
        minute_data = StockMinuteData.objects.filter(
            ts_code=ts_code,
            trade_time__date__gte=datetime.strptime(start_date, '%Y%m%d')          
        ).order_by('trade_time')


        pre_close_data_list = DailyData.objects.filter(
            ts_code=ts_code,
            trade_date__lte=latest_date.date().strftime('%Y%m%d')
        ).order_by('-trade_date')[:5].values('pre_close','trade_date')
        pre_close_data_list = list(pre_close_data_list)
        
        # 准备返回数据
        results = {
            'ts_code': ts_code,
            'data': []
        }
        
        for data in minute_data:
            trade_date_str = data.trade_time.date().strftime('%Y%m%d')
            pre_close = [pre_close_data['pre_close'] for pre_close_data in pre_close_data_list if pre_close_data['trade_date'] == trade_date_str]
            results['data'].append({
                'time': data.trade_time.astimezone().strftime('%Y-%m-%d %H:%M'),  # 转换为本地时区
                'price': float(data.close),
                'vol': int(data.vol),#只保留成交量
                # 'amount':float(data.amount / 10000),#以万元为单位
                'avg_price':float(data.avg_price),
                'pre_close':pre_close[0] if len(pre_close) >= 1 else 0
            })
        # print(f'minute of stock results: {results["data"]}')
            
        return JsonResponse(results)
# 股票涨停数据,实际上是涨幅大于9%的股票
class StockEnergyZtView(APIView):
    """
    获取最新交易日涨幅大于9%的个股数据
    """
    def get(self, request):
        # 获取最新交易日
        latest_record = DailyData.objects.order_by('-trade_date').first()
        if not latest_record:
            return JsonResponse({"error": "没有找到交易数据"}, status=404)
        latest_date = latest_record.trade_date

        # 查询涨幅大于9%的个股
        stocks = DailyData.objects.filter(
            trade_date=latest_date,
            pct_chg__gt=9
        ).values('ts_code', 'close', 'pct_chg', 'amount').order_by('-pct_chg')

        if not stocks:
            return JsonResponse({"message": "没有找到涨幅大于9%的个股"}, status=200)

        # 整合数据
        results = []
        for stock in stocks:
            ts_code = stock['ts_code']
            # 获取股票名称
            stock_basic = StockBasic.objects.filter(ts_code=ts_code).first()
            name = stock_basic.name if stock_basic else "未知"

            # 获取每日指标数据
            daily_basic = DailyBasic.objects.filter(
                ts_code=ts_code,
                trade_date=latest_date
            ).first()
            turnover_rate_f = daily_basic.turnover_rate_f if daily_basic else None
            circ_mv = daily_basic.circ_mv if daily_basic else None

            results.append({
                "ts_code": ts_code,
                "name": name,
                "close": stock['close'],
                "pct_chg": stock['pct_chg'],
                "amount": stock['amount'],
                "turnover_rate_f": turnover_rate_f,
                "circ_mv": circ_mv
            })

        return JsonResponse({"latest_date": latest_date, "stocks": results}, safe=False)
    

class StockDailyKLineView(APIView):
    """
    获取个股日K线数据
    默认获取近两年的数据，但前端只显示近三个月的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SZ')
        
        # 计算近两年的日期
        # end_date = datetime.now()
        # start_date = end_date - timedelta(days=365*2)
        
        # 从IndexDaily表中获取数据
        kline_data = DailyData.objects.filter(
            ts_code=ts_code,
            # trade_date__gte=start_date.strftime('%Y%m%d')
        ).order_by('trade_date')

        print(f'kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount * 0.001, # 成交量,以百万为单位，兼容个股
                'pre_close':data.pre_close
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        # print(f'results: {results}')
        return Response(results)


class StockWeeklyKLineView(APIView):
    """
    获取个股周K线数据
    默认获取近两年的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SZ')
        
        # 从StockKDataWeekly表中获取数据
        kline_data = StockKDataWeekly.objects.filter(
            ts_code=ts_code,
        ).order_by('trade_date')

        print(f'weekly_kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount* 0.000001,  # 成交量，以亿为单位
                'pre_close':data.pre_close
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        return Response(results)


class StockMonthlyKLineView(APIView):
    """
    获取指数月K线数据
    默认获取近五年的数据
    """
    def get(self, request):
        # 获取请求参数，默认为上证指数
        ts_code = request.GET.get('ts_code', '000001.SH')
        
        # 从StockKDataMonthly表中获取数据
        kline_data = StockKDataMonthly.objects.filter(
            ts_code=ts_code,
        ).order_by('trade_date')

        print(f'monthly_kline_data length: {len(kline_data)}')
        
        # 准备返回数据
        dates = []
        candles = []
        
        for data in kline_data:
            # 将日期格式化为YYYY-MM-DD
            date_str = data.trade_date
            if len(date_str) == 8:  # 格式为YYYYMMDD
                formatted_date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
            else:
                formatted_date = date_str
                
            dates.append(formatted_date)
            candles.append({
                'open': data.open,
                'close': data.close,
                'high': data.high,
                'low': data.low,
                'amount': data.amount* 0.000001,  # 成交量，以百万为单位
                'pre_close':data.pre_close
            })
        
        results = {
            'ts_code': ts_code,
            'dates': dates,
            'candles': candles
        }
        return Response(results)
    
class StockInfoView(APIView):
    """
    根据个股代码获取相关信息：名称、最新价格、涨幅、成交金额、换手率、量比、流通值、流通股、总市值、总股数、行业、地域、沪深股通、市盈率、市净率、股息率。
    """
    def get(self, request):
        # 获取请求参数，默认为空
        ts_code = request.GET.get('ts_code', '')
        if not ts_code:
            return JsonResponse({"error": "请输入个股代码"}, status=400)

        # 从DailyData获取最新价格、涨幅、成交金额
        daily_data = DailyData.objects.filter(ts_code=ts_code).order_by('-trade_date').first()
        if not daily_data:
            return JsonResponse({"error": "未找到该个股的交易数据"}, status=404)

        # 从DailyBasic获取换手率、量比、流通值、流通股、总市值、总股数、市盈率、市净率、股息率
        daily_basic = DailyBasic.objects.filter(ts_code=ts_code, trade_date=daily_data.trade_date).first()
        if not daily_basic:
            return JsonResponse({"error": "未找到该个股的每日指标数据"}, status=404)

        # 从StockBasic获取名称、行业、地域、沪深股通
        stock_basic = StockBasic.objects.filter(ts_code=ts_code).first()
        if not stock_basic:
            return JsonResponse({"error": "未找到该个股的基本信息"}, status=404)


        # 构建返回数据，并处理NaN值
        def replace_nan(value):
            import math
            return -1 if value is None or (isinstance(value, float) and math.isnan(value)) else value

        results = {
            "ts_code": ts_code,
            "name": stock_basic.name,
            "close": replace_nan(daily_data.close),
            "change": replace_nan(daily_data.change),
            "pct_chg": replace_nan(daily_data.pct_chg),
            "amount": replace_nan(daily_data.amount),
            "turnover_rate_f": replace_nan(daily_basic.turnover_rate_f),
            "volume_ratio": replace_nan(daily_basic.volume_ratio),
            "circ_mv": replace_nan(daily_basic.circ_mv),
            "float_share": replace_nan(daily_basic.float_share),
            "total_mv": replace_nan(daily_basic.total_mv),
            "total_share": replace_nan(daily_basic.total_share),
            "industry": stock_basic.industry,
            "area": stock_basic.area,
            "is_hs": stock_basic.is_hs,
            "pe": replace_nan(daily_basic.pe),
            "pb": replace_nan(daily_basic.pb),
            "dv_ratio": replace_nan(daily_basic.dv_ratio)
        }

        return JsonResponse(results)
        